/**
 * Handelt alle Requests und Informs ab
 */
package de.fhin.mas.agents.navigator.behaviours;

import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.util.leap.List;
import de.fhin.mas.MASEvents;
import de.fhin.mas.agents.navigator.NavigatorAgent;
import de.fhin.mas.ontology.EnvironmentScanResult;
import de.fhin.mas.ontology.RelativeDistance;
import de.fhin.mas.ontology.TargetSearchResult;
import de.fhin.mas.util.MessageUtil;
import de.fhin.mas.util.RelativeCoordinate;

/**
 * @author Mike
 * @author Matthias Wilhelm
 */

public class MsgHandlerCyclic extends CyclicBehaviour {

	/**
	 * ID
	 */
	private static final long serialVersionUID = -1523700191022643430L;

	/**
	 * Templates um verschiedene Messages abzuholen
	 */

	MessageTemplate target_found = MessageUtil.buildBasicCommunicationTemplate(
			null, MASEvents.TARGET_FOUND.getName(), ACLMessage.INFORM, null);
	MessageTemplate object_loaded = MessageUtil
			.buildBasicCommunicationTemplate(null, MASEvents.OBJECT_LOADED
					.getName(), ACLMessage.INFORM, null);
	MessageTemplate object_lost = MessageUtil.buildBasicCommunicationTemplate(
			null, MASEvents.OBJECT_LOST.getName(), ACLMessage.INFORM, null);
	MessageTemplate system_stop_required = MessageUtil
			.buildBasicCommunicationTemplate(null,
					MASEvents.SYSTEM_STOP_REQUIRED.getName(),
					ACLMessage.INFORM, null);
	MessageTemplate environment_scan_finished = MessageUtil
			.buildBasicCommunicationTemplate(null,
					MASEvents.ENVIRONMENT_SCAN_FINISHED.getName(),
					ACLMessage.INFORM, null);

	@Override
	public void action() {

		ACLMessage msg = null;

		/**
		 * Hier wird geprueft ob eine Nachricht des Typs MASEvent.TARGET_FOUND
		 * abgeholt wurde
		 * 
		 */
		if ((msg = myAgent.receive(target_found)) != null) {
			/**
			 * Ziel wurde gefunden und kann angefahren werden
			 */
			TargetSearchResult target = null;
			if (msg.getContent() != null) {
				target = ((NavigatorAgent) myAgent)
						.extractTargetSearchResultFromMsg(msg);
			}
			if (target != null) {
				((NavigatorAgent) myAgent)
						.set_myDestination(new RelativeCoordinate(target
								.getAngle(), target.getDistance()));
				((NavigatorAgent) myAgent).target_object();

			}
		}

		/**
		 * Hier wird geprueft ob eine Nachricht des Typs MASEvent.OBJECT_LOADED
		 * abgeholt wurde
		 */
		else if ((msg = myAgent.receive(object_loaded)) != null) {
			// TODO: Greifer sagt uns wohin Objekt gebracht werden soll??
			((NavigatorAgent) myAgent).target_storage();

		}

		/**
		 * Hier wird geprueft ob eine Nachricht des Typs MASEvent.OBJECT_LOST
		 * abgeholt wurde Wenn dieses Event versendet wurde muss die Plattform
		 * gestoppt werden TODO: Suchauftrag neu starten? -> Object weg ->
		 * wieder gefundenes Objekt anfahren -> zum Lager fahren
		 */
		else if ((msg = myAgent.receive(object_lost)) != null) {
			// Plattform anhalten
			((NavigatorAgent) myAgent).stop();

		} else if ((msg = myAgent.receive(environment_scan_finished)) != null) {
			EnvironmentScanResult scanResult = null;
			if (msg.getContent() != null) {
				scanResult = ((NavigatorAgent) myAgent)
						.extractEnvironmentScanResultFromMsg(msg);
			}
			if (scanResult != null) {
				List obstacles = scanResult.getObstacles();
				RelativeCoordinate[] obstacle = new RelativeCoordinate[obstacles
						.size()];
				RelativeDistance[] rD = new RelativeDistance[obstacles.size()];
				for (int i = 0; i < obstacles.size(); i++) {
					rD[i] = (RelativeDistance) obstacles.get(i);
					obstacle[i] = new RelativeCoordinate(rD[i].getAngle(),
							rD[i].getDistance());
					int distance = obstacle[i].getCoordinate(0).getX();
					// Wenn der seitliche Abstand des Hinternisses kleiner als
					// 1m ist muss ausgewichen werden
					if (distance != -1) {
						if (Math.abs(distance) < 100) {
							// TODO: Ausweich-Alghoritmus starten!
						}
					}
				}

			}
			// TODO: Berechnen ob Obstacles im Weg des Roboters liegen
			// falls ja ausweichen starten
			// dazu nextMove neu berechnen und indirekt an Drive-Behaviour
			// übergeben
		}

		/**
		 * Wenn Nachricht nicht fuer dieses Behaviour bestimmt ist gehe schlafen
		 */
		else {

			/**
			 * Wenn Nachricht fuer einen anderen bestimmt ist blocken und auf
			 * naechste Nachricht warten
			 */
			block();
		}

	}
}
